package br.com.damazzy.util.componentes
{
	import br.com.damazzy.util.FormatUtil;
	import br.com.damazzy.util.FormataNumero;
	
	import flash.events.TextEvent;
	
	import mx.controls.Alert;
	import mx.controls.TextInput;
	import mx.events.FlexEvent;
	import mx.events.ValidationResultEvent;
	import mx.formatters.NumberBaseRoundType;
	import mx.validators.Validator;

	public class CampoNumerico extends TextInput {
		
		public static const CASAS_DECIMAIS_TRUNCAR: String = NumberBaseRoundType.NONE;
		
		private var formato: String = "";
		private var _valor: Number = 0;
		private var _casasDecimais: int = 0;
		private var _agruparDigitos: Boolean = true;
		private var _arredondamento: String = CASAS_DECIMAIS_TRUNCAR;
		protected var _validarObrigatorio: Boolean = false;
		protected var _validarMensagem: String = "";
		protected var valid: Validator = null;
		private var valorOriginal: String;
		private var _travarDigitacaoCasasDecimais:Boolean = true;
		private var _aceitaNulos:Boolean = false;
		private var _valorMinimo:Number;
		private var _valorMaximo:Number;
		
		public function CampoNumerico() {
			super();
			
			this.addEventListener(FlexEvent.CREATION_COMPLETE, init);
			this.addEventListener("change", validHandler);
			this.addEventListener("focusOut", validHandler_focusOut);
			this.addEventListener("focusIn", validHandler_focusIn);
			this.addEventListener(TextEvent.TEXT_INPUT, interceptChar); //trata valor digitado
		}
		
		private function init(event: FlexEvent): void {
			
			this.restrict = "0123456789.,";
			this.setStyle("textAlign", "right");
			
			if(this.text != "") {
				this.text = FormataNumero.formata(_valor, _casasDecimais, _agruparDigitos, _arredondamento);
			}	
		}
		
		/**
	     *  pega valor digitado no campo textoe  transforma em valor numérico
	     */	
		protected function pegaValor():Number {
			var str:String = this.text;
			var patAgr:RegExp;
			
			if(formato == null || formato == "") {
				patAgr = /\./g; //expressão para localizar pontos (.)
				
				str = str.replace(patAgr, "").replace(",", "."); //localiza pontos e retira e localiza a vírgula e troca por ponto(.)
			}else{
				patAgr = /\-/g; //expressão para localizar traços
				str = str.replace(patAgr, ""); //
				
				patAgr = /\//g; //expressão para localizar barras
				str = str.replace(patAgr, ""); //
				
				patAgr = /\./g; //expressão para localizar barras
				str = str.replace(patAgr, ""); //
			}
			
			return Number(str);
		}
		
		/**
	     * Função que realiza validação
	     * 
		 * @return Retorna <code>true</code> caso o campo esteja preenchido ou <code>false</code> caso o campo não esteja preenchido
	     */
		public function validar():Boolean{
			
			if(valid == null) {
				valid = new Validator(); //cria validador
			}
			
			valid.required = _validarObrigatorio; //determina se é requerido
			valid.requiredFieldError = (_validarMensagem == "" ?
										"Campo de preenchimento obrigatório!" :
										_validarMensagem); //determina mensagem
			valid.source = this; //seta campo para validar
			valid.property = "text"; //propriedade a verificar
			
			if (valid.validate().type == ValidationResultEvent.INVALID) //efetua validação
				return false;
			else
				return true;
		}
		
		/**
	     *  chama validador
	     */	
		private function validHandler(obj:Object):void{
			validar();
		}
		
		/**
	     *  tratamento para o campo ao perder foco
	     */		
		protected function validHandler_focusOut(obj:Object):void {
			validar(); //chama validador
			
			var vlrPrev:Number = pegaValor(); // atualiza valor com o texto digitado
			
			if(!isNaN(_valorMinimo)) {
				if(vlrPrev < _valorMinimo) {
					Alert.show("Valor menor que o valor mínimo informado (" + _valorMinimo + ").", "Atenção");
					return;
				}
			}
			
			if(!isNaN(_valorMaximo)) {
				if(vlrPrev > _valorMaximo) {
					Alert.show("Valor maior que o valor máximo informado (" + _valorMaximo + ").", "Atenção");
					return;
				}
			}
			
			_valor = vlrPrev;
			
			if(formato == "" || formato == null)
				formatarNumero(); //se não houver formato determinado manda formatar como valor numérico padrão
			else {
				if (!aceitaNulos || this.text.length > 0) {
					if(this.text.length == 0)
					{
						this.text = "";	
					}
					else
					{
						this.text = FormatUtil.formataValor(_valor, formato); //caso tenha algum formato determinado manda aplicar							
					}
				}
				else
				{
					if(this.text.length == 0)
					{
						this.text = "";
					}
				}
			}
		}
		
		/**
	    *  Efetua validações de para o item digitado
	    */	
		private function interceptChar(event:TextEvent):void{
			var input:String = event.text; //pega item digitado

			if(input == "") { //Firefox pega a tecla ALT como um CHAR digitado
				event.preventDefault();
				return;
			}			
				
			//verifica se vai permitir digitar maior quantidade de casas decimais do que o configurado
			if(_travarDigitacaoCasasDecimais && _casasDecimais > 0 && this.selectionBeginIndex == this.selectionEndIndex) {
				
				//pega local do separador
				var indSeparadorDecimal:int = this.text.indexOf(",");
				
				//verifica se existe um separador digitado
				if(indSeparadorDecimal != -1 && this.selectionBeginIndex > indSeparadorDecimal) {
					//calcula a quantidade de casas decimais existentes para travar
					if(((this.text.length - 1) - indSeparadorDecimal) == _casasDecimais){
						event.preventDefault();
						return;
					}
				}
			}
			
			if(input == "," || input == "."){ //verifica se foi uma vírgula digitada				
				
				if(_casasDecimais == 0){ //caso o campo não tenha casas decimais cancela item digitado
					event.preventDefault();
					return;
				}

				//se todo o texto estiver selecionado para a validação por aqui
				if(this.selectionBeginIndex == 0 && this.selectionEndIndex == this.text.length){
					event.preventDefault();
					this.text = "0,";
					this.selectionBeginIndex = 2; //posiciona o cursor no final
					this.selectionEndIndex = 2;
					
					return;
				}
				
				if(this.text == ""){ // caso o campo esteja vazio adiciona um 0 antes da vírgula
					event.preventDefault();//cancela digitação da vírgula
					this.text = "0,"; //monta a vírgula com um zero
					this.selectionBeginIndex = 2; //posiciona o cursor no final
					this.selectionEndIndex = 2;
					return;
				}
				if(this.text.indexOf(",") != -1){ //caso já exista uma vírgula digitada cancela a digitação de uma segunda vírgula
					event.preventDefault();
					return;
				}
				
				if(input == "."){
					event.preventDefault();
					var strP1:String = this.text.substr(0, this.selectionBeginIndex);
					var strP2:String = this.text.substr(this.selectionEndIndex);
					
					var posTemp:int = this.selectionBeginIndex + 1;
					
					this.text = strP1 + "," + strP2;
					
					this.selectionBeginIndex = posTemp;
					this.selectionEndIndex = posTemp;

					return;
				}
			}
			if(input == "-") { //verifica sinal de negativo digitado
				if(this.text.indexOf("-") >= 0){ //caso já exista um sinal digitado cancela digitação do segundo
					event.preventDefault();
					return;
				}
				if(this.selectionBeginIndex != 0){ //caso o sinal não esteja no primeito ítem cancela digitação
					event.preventDefault();
					return;
				}
			}
			
		}
		
		/**
	    * Aplica formatação no valor
	    */	
		protected function formatarNumero():void{
			if(this.text != "")
				this.text = FormataNumero.formata(_valor, _casasDecimais, _agruparDigitos, _arredondamento);
		}
		
		/**
	     *  tratamento para o campo ao receber foco
	     */		
		protected function validHandler_focusIn(obj:Object):void{
			if(this.formato != "")
				this.text = valorOriginal;
		}
		
		public function get valor():Number {
			return pegaValor();
		}
		public function set valor(vlr:Number):void {
			_valor = vlr;
			this.text = FormataNumero.formata(_valor, _casasDecimais, _agruparDigitos, _arredondamento);
		}
		
		/**
	     * Formato para o valor digitado, este formato é aplicado ao perder o foco do campo 
	     * 
	     * @default ""
	     */		
		public function get Formato():String {
			return formato;
		}
		public function set Formato(vlr:String):void {
			formato = vlr;
		}
		
		/**
	     * Número de casas decimais para valor digitado 
	     * 
	     * @default 0
	     */		
		public function get casasDecimais():int{
			return _casasDecimais;
		}
		public function set casasDecimais(valor:int):void{
			_casasDecimais = valor;
		}
		
		/**
	     * Determina se é necessário agrupar dígitos na formatação do valor digitado 
	     * 
	     * @default true
	     */		
		public function get agruparDigitos():Boolean {
			return _agruparDigitos;
		}
		public function set agruparDigitos(vlr:Boolean):void {
			_agruparDigitos = vlr;
		}
		
		/**
	     * habilita o arredondamento do valor digitado 
	     * 
	     * @default false
	     */		
		public function get arredondamento():String {
			return _arredondamento;
		}
		public function set arredondamento(vlr:String):void {
			_arredondamento = vlr;
		}
		
		/**
	     * Determina se campo é requerido 
	     * 
	     * @default false
	     */		
		public function get validarObrigatorio():Boolean{
			return _validarObrigatorio;
		}
		public function set validarObrigatorio(vlr:Boolean):void{
			_validarObrigatorio = vlr;
			
			validar(); //chama validador
		}
		
		/**
	     * Mensagem de exibidação da validação 
	     * 
	     * @default ""
	     */	
		public function get validarMensagem():String{
			return _validarMensagem;
		}
		public function set validarMensagem(vlr:String):void{
			_validarMensagem = vlr;
			
			validar(); //chama validador
		}
		
		/**
	     * Informa se o componente pode receber valores em branco(nulo) 
	     * 
	     * @default false
	     */				
		public function set aceitaNulos(value:Boolean):void {
            _aceitaNulos = value;
        }
        
        public function get aceitaNulos():Boolean {
            return _aceitaNulos;
        }
        
        /**
	     * Override da propriedade text 
	     * 
	     * @default ""
	     */		    
		public override function get text():String{
			return super.text;
		}

		public override function set text(vlr:String):void{
			valorOriginal = vlr;
			super.text = vlr;
		}
		
		/**
	     * limita a digitação das casas decimais configurada na propriedade casasDecimais 
	     * 
	     * @default false
	     */	
		public function get travarDigitacaoCasasDecimais():Boolean {
			return _travarDigitacaoCasasDecimais;
		}
		public function set travarDigitacaoCasasDecimais(vlr:Boolean):void {
			_travarDigitacaoCasasDecimais = vlr;
		}
		
		/**
	     * Valor mínimo que o componente pode receber 
	     * 
	     * @default null
	     */	
		public function get valorMinimo():Number {
			return _valorMinimo;
		}
		public function set valorMinimo(vlr:Number):void {
			_valorMinimo = vlr;
		}

		/**
	     * Valor máximo que o componente pode receber 
	     * 
	     * @default null
	     */	
		public function get valorMaximo():Number {
			return _valorMaximo;
		}
		public function set valorMaximo(vlr:Number):void {
			_valorMaximo = vlr;
		}
	}
}